#include "Entity.h"
#include "Game.h"
#include "Model3DInstance.h"
#include "PhysicEntityInstance.h"
#include "PhysicShape.h"
#include "PhysicManager.h"
#include "Tools.h"
#include "ModelsManager.h"

#include <tinyxml.h>

Entity::Entity()
{
	mRenderDistanceMin = 0;
	mRenderDistanceMax = 10000;
	mIsStatic = true;
	mPosition = XMFLOAT3(0,0,0);
	mPhysicEntityInstance = NULL;
	mIsRendering = false;
}

Entity::Entity(const Entity& pToCopy)
{


}

Entity::~Entity()
{

}

Entity Entity::operator=(Entity const& pToCopy)
{
	return pToCopy;
}

bool Entity::Initialize(Model3D *pModel, PhysicShape *pPhysicShape, bool pIsStatic, XMFLOAT3 pPosition, XMFLOAT4 pOrientation)
{
	Model3DInstance* model3DInstances = new Model3DInstance();
	model3DInstances->Initialize(pModel, pPosition, pOrientation);

	mModel3DInstances.push_back(model3DInstances);

	mPhysicEntityInstance = new PhysicEntityInstance();
	mPhysicEntityInstance->Initialize(pPhysicShape, pIsStatic, pPosition, pOrientation,this);

	return true;
}

void Entity::InitializeByXml(TiXmlElement* entityElement)
{
	mGame = Game::Instance();
	const char* strPosition = entityElement->Attribute("position");
	GetVector3D(strPosition, mPosition);

	const char* strRotation = entityElement->Attribute("rotation");
	if(strRotation != 0) mRotation = StringToQuaternion(strRotation);
	else XMStoreFloat4(&mRotation,XMQuaternionIdentity());

	mIsStatic = std::string(entityElement->Attribute("static")) == std::string("true");

	TiXmlElement* model3DInstance = entityElement->FirstChildElement( "Model3DInstance" );
	for( model3DInstance; model3DInstance; model3DInstance=model3DInstance->NextSiblingElement("Model3DInstance") )
	{
		int modelId = ::atoi(model3DInstance->Attribute("model3d"));
		float renderDistanceMin = (float)::atof(model3DInstance->Attribute("minDistance"));
		float renderDistanceMax = (float)::atof(model3DInstance->Attribute("maxDistance"));

		Model3DInstance* model3DInstances = new Model3DInstance();
		model3DInstances->SetRenderDistance(renderDistanceMin, renderDistanceMax);
		
		model3DInstances->Initialize(ModelsManager::Instance()->GetModel(modelId), mPosition, mRotation);
		mModel3DInstances.push_back(model3DInstances);
	}

	TiXmlElement* physicShapeInstance = entityElement->FirstChildElement( "PhysicShapeInstance" );

	if(physicShapeInstance != NULL)
	{
		int physicShapeId = ::atoi(physicShapeInstance->Attribute("physicShape"));
		mPhysicEntityInstance = new PhysicEntityInstance();
		mPhysicEntityInstance->Initialize(mGame->GetPhysicShape(physicShapeId), mIsStatic, mPosition, mRotation, this);
	}

}

void Entity::Uninit()
{

}

void Entity::Update(int pElapsedTime)
{
	for(std::vector<Model3DInstance*>::iterator entity = mModel3DInstances.begin();entity != mModel3DInstances.end();++entity)
	{
		if(mPhysicEntityInstance != NULL)
		{
			XMFLOAT4X4 tranform = mPhysicEntityInstance->GetTransform();
			(*entity)->setTransform(tranform);
		}
	}
}

void Entity::PreRender()
{
	XMFLOAT3 origine = mGame->GetOrigine();
	float distance = 0;
	if(mIsStatic)
	{
		 XMStoreFloat(&distance, XMVector3Length(XMLoadFloat3(&origine) - XMLoadFloat3(&mPosition)));
	}
	else
	{
		XMStoreFloat(&distance, XMVector3Length(XMLoadFloat3(&origine) - XMLoadFloat3(&mPosition)));
	}

	if(mRenderDistanceMin < distance && distance < mRenderDistanceMax)
	{
		//Detect start rendering event
		if(!mIsRendering)
		{
			EventStartRendering();
			mIsRendering = true;
		}

		for(std::vector<Model3DInstance*>::iterator mod3dInstance = mModel3DInstances.begin();mod3dInstance != mModel3DInstances.end();++mod3dInstance)
		{
			(*mod3dInstance)->PreRender(distance);
		}
	}
	else
	{
		NoRender();
	}
}

void Entity::NoRender()
{
	if(mIsRendering)
	{
		mIsRendering = false;
		EventStopRendering();
	}

	for(std::vector<Model3DInstance*>::iterator mod3dInstance = mModel3DInstances.begin();mod3dInstance != mModel3DInstances.end();++mod3dInstance)
	{
		(*mod3dInstance)->StopRender();
	}

}

void Entity::EventStartRendering()
{

}

void Entity::EventStopRendering()
{
	
}

void Entity::Render()
{


}

//void Entity::ShadowRender(ShadowMap* pShadowMap)
//{
//	for(std::vector<Model3DInstance*>::iterator mod3dInstance = mModel3DInstances.begin();mod3dInstance != mModel3DInstances.end();++mod3dInstance)
//	{
//		(*mod3dInstance)->ShadowRender(pShadowMap);
//	}
//}

void Entity::GetBoundingBox(BoundingBox &pBoundingBox)
{
	bool first = true;
	BoundingBox tmpBoundingBox;
	for(std::vector<Model3DInstance*>::iterator mod3dInstance = mModel3DInstances.begin();mod3dInstance != mModel3DInstances.end();++mod3dInstance)
	{
		if( first )
		{
			(*mod3dInstance)->GetBoundingBox(pBoundingBox);
			first = false;
		}
		else
		{
			(*mod3dInstance)->GetBoundingBox(tmpBoundingBox);
			AddBoundingBox(pBoundingBox, tmpBoundingBox);
		}
	}
}

void Entity::ApplyTransformToMesh(int pMeshIndex, const XMFLOAT4X4 &pTransform)
{
	mModel3DInstances.front()->ApplyTransformToMesh(pMeshIndex, pTransform);
}

void Entity::SetPosture(std::string pPostureName)
{
	mModel3DInstances.front()->SetPosture(pPostureName);
}

void Entity::SetNextPosture(std::string pPostureName)
{
	mModel3DInstances.front()->SetNextPosture(pPostureName);
}

void Entity::SetPostureAmount(float pAmount)
{
	mModel3DInstances.front()->SetPostureAmount(pAmount);
}

bool Entity::IsStatic()
{
	return mIsStatic;
}

void Entity::ApplyForce(XMFLOAT3 pForce, XMFLOAT3 pPosition)
{
	mPhysicEntityInstance->ApplyForce(pForce, pPosition);

}